﻿using System;

namespace Quicklight.Web {

   /// <summary>
   /// The Validation class validates the value returned by the Value property of a class that implements the IObservable interface
   /// If the ValueChanged event of the supplied IObservable is fired, the protected OnValueChanged is called.
   /// To create a custom Validation class inherit from Validation and override the OnValueChanged method.
   /// In the OnValueChanged method call the Value property on the Observable property, validate the value and set the appropriate message in the Message property
   /// </summary>
   public class Validation {
      private string message;
      private IObservable observable;

      /// <summary>
      /// Constructs a Validation class, with no IObservable specified
      /// </summary>
      public Validation() {
         this.message = "";
      }

      /// <summary>
      /// Constructs a Validation object with the specified IObservable instance. 
      /// Wire up the events so that if the ValueChanged event of the IObservable is fired, the Validation instance will call OnValueChanged
      /// Also calls OnValueChanged to set the validation message
      /// </summary>
      /// <param name="observable">IObservable instance which must be observed and validated</param>
      public Validation(IObservable observable) {
         this.message = "";
         this.observable = observable;

         if (this.observable != null)
            this.observable.ValueChanged += new EventHandler(observable_ValueChanged);
         
         OnValueChanged();
      }

      /// <summary>
      /// This event is fired if the validation message changes
      /// </summary>
      public event EventHandler MessageChanged;

      /// <summary>
      /// If there is a not-null validation message, this returns false, else returns true
      /// </summary>
      public bool Failed {
         get { return !String.IsNullOrEmpty(Message); }
      }

      /// <summary>
      /// Gets and sets the validation message. Set the validation message from OnValueChanged if the value of the observable fails validation
      /// </summary>
      public string Message {
         get {
            return this.message;
         }
         set {
            if (this.message == value)
               return;

            this.message = value;
            OnMessageChanged();
         }
      }
      
      /// <summary>
      /// IObservable that must be observed and whose value must be validated if it changes.
      /// Setting this property wires up the event ValueChanged of the IObservable so that when it fires, OnValueChanged is called
      /// Also, after the IObservable is set, OnValueChanged is also called
      /// </summary>
      public IObservable Observable {
         get {
            return this.observable;
         }
         set {
            if (this.observable != null)
               this.observable.ValueChanged -= new EventHandler(observable_ValueChanged);

            this.observable = value;

            if (this.observable != null)
               this.observable.ValueChanged += new EventHandler(observable_ValueChanged);

            OnValueChanged();
         }
      }

      /// <summary>
      /// Virtaul protected method that is called if the ValueChanged event of the observed IObservable instance is fired.
      /// To do custom validation override this method, call the Value property on the Observable property, validate the value and set the Message property
      /// </summary>
      protected virtual void OnValueChanged() {
      }

      /// <summary>
      /// Fires the MessageChanged event if there are subscribers
      /// </summary>
      private void OnMessageChanged() {
         if (MessageChanged != null)
            MessageChanged(this, EventArgs.Empty);
      }

      /// <summary>
      /// Event handler of the ValueChanged event of the observed IObservable. Calls the OnValueChanged method to do validation
      /// </summary>
      /// <param name="sender">The observed IObservable instance</param>
      /// <param name="e">Equal to EventArgs.Empty</param>
      private void observable_ValueChanged(object sender, EventArgs e) {
         OnValueChanged();
      }
   }
}
